# !/usr/bin/env python
# -*- coding: utf-8 -*-

r"""
@Project     : cospace
@File        : cli/view/local_space_list.py
@Author      : Liu Quan
@Time        : 2024/10/16 10:30
@Description : 本地空间
@IDE         : PyCharm
Copyright (c) 2023 深圳市有为信息技术发展有限公司, All Rights Reserved
"""

import os
import sys

from cospace import *
from cospace.cli import BasePage
from cospace.control_center import ControlCenter
from cospace.space_manager import SpaceInfo, SpaceStatus
from cospace.cli.editor import Editor
from cospace.script.create_settings_cmake_file import CreateSettingsCmakeFile


class LocalSpacesPage(BasePage):

    @classmethod
    def prompt(cls):
        print("-------------------------------")
        print(f"0. 返回首页")
        print(f"1. 复制空间")
        print(f"2. 修改空间")
        print(f"3. 删除空间")
        print(f"4. 激活空间")
        print(f"5. 创建空间")
        print("输入 [0, 1, 2, 3, 4，5], 选择业务")
        print("输入 exit，回车，退出\n")

    @classmethod
    def prompt_with_spaces(cls, spaces):
        for i, item in enumerate(spaces):
            if item.get("status") is not None and item.get("status") == SpaceStatus.CACHE:
                print(f"{i + 1}. {item.get('name')}【缓存】: {item.get('path')}")
            else:
                print(f"{i + 1}. {item.get('name')}: {item.get('path')}")

    @classmethod
    def process(cls, session, **extra_param):

        while True:
            spaces = ControlCenter.get_all_space_path()
            cls.prompt_with_spaces(spaces)
            cls.prompt()

            try:
                user_input = session.prompt('请选择业务[0, 1, 2, 3, 4，5]：').strip()
                if user_input.lower() == 'exit':
                    sys.exit("Exiting...")

                if user_input == "0":
                    # 返回首页
                    return

                if user_input == "1":
                    # 复制空间
                    if len(spaces) == 0:
                        print("没有可复制的空间")
                        continue

                    ReplicateSpacePage.process(session)

                elif user_input == "2":
                    # 修改空间
                    if len(spaces) == 0:
                        print("没有可修改的空间")
                        continue

                    user_input = session.prompt(f'请输入空间索引[1: {len(spaces)}]：').strip()
                    # 校验 index, 是否是整型, 是否是有效的空间索引
                    if not str.isdigit(user_input):
                        print("无效的空间索引.")
                        if len(spaces) == 1:
                            print(f"请输入整数.")
                        else:
                            print(f"请输入 [1 ~ {len(spaces)}] 之间的整数.")
                        continue

                    user_input = int(user_input)
                    if user_input < 0 or user_input > len(spaces):
                        print("无效的空间索引.")
                        print(f"请输入 [1 ~ {len(spaces)}] 之间的整数.")
                        continue

                    space_info = spaces[user_input - 1]
                    space_path = space_info.get("path")
                    tgt_path = os.path.join(space_path, "settings.json") if not space_path.endswith(".json") else space_path
                    print(f"开始编辑空间：{tgt_path}")
                    editor = Editor(tgt_path)
                    editor.run()
                    print(f"编辑空间成功")

                elif user_input == "3":
                    if len(spaces) == 1:
                        user_input = session.prompt(f'请输入空间索引[1]：').strip()
                    else:
                        user_input = session.prompt(f'请输入空间索引[1: {len(spaces)}]：').strip()

                    # 校验 index, 是否是整型, 是否是有效的空间索引
                    if not str.isdigit(user_input):
                        print("无效的空间索引.")
                        if len(spaces) == 1:
                            print(f"请输入整数.")
                        else:
                            print(f"请输入 [1 ~ {len(spaces)}] 之间的整数.")
                        continue

                    user_input = int(user_input)
                    if user_input < 0 or user_input > len(spaces):
                        print("无效的空间索引.")
                        print(f"请输入 [1 ~ {len(spaces)}] 之间的整数.")
                        continue

                    ControlCenter.del_cache_space(spaces[user_input - 1].get("name"))
                    print(f"删除空间成功")
                elif user_input == "4":
                    if len(spaces) == 1:
                        user_input = session.prompt(f'请输入空间索引[1]：').strip()
                    else:
                        user_input = session.prompt(f'请输入空间索引[1: {len(spaces)}]：').strip()

                    # 校验 index, 是否是整型, 是否是有效的空间索引
                    if not str.isdigit(user_input):
                        print("无效的空间索引.")
                        if len(spaces) == 1:
                            print(f"请输入整数.")
                        else:
                            print(f"请输入 [1 ~ {len(spaces)}] 之间的整数.")
                        continue

                    user_input = int(user_input)
                    if user_input < 0 or user_input > len(spaces):
                        print("无效的空间索引.")
                        print(f"请输入 [1 ~ {len(spaces)}] 之间的整数.")
                        continue

                    # 将改空间配置中的属性加入到环境变量中
                    ControlCenter.activate_space(spaces[user_input - 1].get("name"))
                    print(f"激活空间成功")
                elif user_input == "5":
                    # 创建空间
                    print(f"开始创建空间")
                    space_name = session.prompt('请输入新空间名称：').strip()
                    if not space_name:
                        print("新空间名称不能为空.")
                        continue

                    space_info = ControlCenter.get_space_info(space_name)
                    if space_info:
                        print(f"新空间名称已经存在.({space_info})")
                        print("请重新输入新空间名称.")
                        continue

                    space_path = session.prompt('请输入新空间路径：').strip()
                    # 获取当前系统是 windows 还是 linux，判断 space_path+venv/python 是否存在
                    if os.path.exists(os.path.join(space_path, "venv", "python.exe")) or os.path.exists(os.path.join(space_path, "venv", "bin", "python")):
                        print(f"新空间路径已经存在Python环境.({space_info})")
                        print("请重新输入新空间路径.")
                        continue

                    if not space_path:
                        print("新空间路径不能为空.")
                        continue

                    if os.path.exists(space_path):
                        print("新空间路径已经存在.")
                        continue

                    # 创建新的 settings.json 文件
                    CreateSettingsCmakeFile.create_settings_file(space_name, space_path)
                    ControlCenter.update_space_record(space_name, space_path)
                    print(f"创建空间成功")

            except KeyboardInterrupt:
                continue
            except EOFError:
                break


class CreateSpacePage(BasePage):
    """
    创建空间页面
    """
    new_space_name = ""  # 空间名
    new_space_path = ""  # 空间路径
    env_yml_content = ""  # env yml 内容
    settings_content = ""  # settings.json 内容
    py_version = ""  # python 版本

    @classmethod
    def prompt(cls):
        print("-------------------------------")
        print(f"0. 返回首页")
        print(f"1. 编辑新空间名称: {cls.new_space_name}")
        print(f"2. 编辑新空间路径: {cls.new_space_path}")
        print(f"3. 编辑新空间配置:")
        print(f"4. 编辑 settings.json 配置")
        print(f"5. Python版本(默认3.11.9): {cls.py_version}")
        print(f"6. 开始创建空间")
        print("输入 exit，回车，退出\n")
        print("输入 [0, 1，3，4，5，6], 选择业务：")

    @classmethod
    def process(cls, session):
        cls.reset_attr()

        while True:
            cls.prompt()

            op_index = session.prompt('请选择业务[0, 1, 2, 3, 4， 5, 6]：').strip()
            if op_index.lower() == 'exit':
                sys.exit("Exiting...")
            if op_index == "0":
                # 返回上级
                return

            try:
                if op_index == "1":
                    space_name = session.prompt(f'请输入新空间名称: ').strip()

                    if not space_name:
                        print("新空间名称不能为空.")
                        continue

                    space_info = ControlCenter.get_space_info(space_name)
                    if space_info:
                        print(f"新空间名称已经存在.({space_info})")
                        print("请重新输入新空间名称.")
                        continue

                    cls.new_space_name = space_name
                    continue

                elif op_index == "2":
                    space_path = session.prompt('请输入新空间路径：').strip()
                    # 获取当前系统是 windows 还是 linux，判断 space_path+venv/python 是否存在
                    if os.path.exists(os.path.join(space_path, "venv", "python.exe")) or os.path.exists(os.path.join(space_path, "venv", "bin", "python")):
                        print(f"新空间路径已经存在Python环境.({space_path})")
                        print("请重新输入新空间路径.")
                        continue
                    cls.new_space_path = space_path

                elif op_index == "3":
                    editor = Editor(content=cls.env_yml_content)
                    result, msg = editor.run()
                    if result:
                        cls.env_yml_content = msg
                        print(f"编辑器退出。")
                    else:
                        print(f"编辑器退出，返回上级菜单，错误信息：{msg}")

                elif op_index == "4":
                    editor = Editor(content=cls.settings_content)
                    result, msg = editor.run()
                    if result:
                        cls.settings_content = msg
                        print(f"编辑器退出。")
                    else:
                        print(f"编辑器退出，返回上级菜单，错误信息：{msg}")

                elif op_index == "5":
                    py_version = session.prompt(f'请输入Python版本(默认3.11.9): ').strip()
                    if not py_version:
                        py_version = "3.11.9"
                    from config import Config
                    if not Config.is_valid_python_version(py_version):
                        print(f"无效的Python版本: {py_version}")
                        print(f"请重新输入Python版本.")
                        continue
                    cls.py_version = py_version

                elif op_index == "6":
                    if not cls.new_space_name:
                        print("请输入新的空间名称.")
                        continue
                    if not cls.new_space_path:
                        print("请输入新的空间路径.")
                        continue
                    if not cls.env_yml_content:
                        print("请编辑新空间配置.")
                        continue
                    if not cls.settings_content:
                        print("请编辑 settings.json 配置.")
                        continue
                    if not cls.py_version:
                        print("请编辑 Python 版本.")
                        continue

                    from cospace.space_manager import SpaceManager
                    from cospace.script.create_settings_cmake_file import CreateSettingsCmakeFile
                    from cospace import PYTHON_ENV_FILE, PYTHON_ENV_FOLDER
                    import subprocess

                    try:
                        # 1. 创建空间目录及信息
                        space_manager = SpaceManager()
                        space_info = space_manager.create_space(cls.new_space_name, cls.new_space_path)
                        # 2. 保存 settings.json
                        if not os.path.exists(cls.new_space_path):
                            os.makedirs(cls.new_space_path, exist_ok=True)
                        settings_path = os.path.join(cls.new_space_path, "settings.json")
                        with open(settings_path, "w", encoding="utf-8-sig") as f:
                            f.write(cls.settings_content)
                        # 3. 保存 environment.yml
                        env_yml_path = os.path.join(cls.new_space_path, PYTHON_ENV_FILE)
                        with open(env_yml_path, "w", encoding="utf-8-sig") as f:
                            f.write(cls.env_yml_content)
                        # 4. 生成 cmake 文件
                        try:
                            CreateSettingsCmakeFile(filepath=settings_path, root_path=cls.new_space_path).create_cmake_file()
                        except Exception as e:
                            print(f"[错误] 生成 CMake 文件失败: {e}")
                            return
                        # 5. 创建 conda 环境
                        env_path = os.path.join(cls.new_space_path, PYTHON_ENV_FOLDER)
                        cmd = [
                            'conda', 'env', 'create',
                            '--prefix', env_path,
                            '-f', env_yml_path,
                            '-y'
                        ]
                        print("\n[Conda] 开始创建环境...\n")
                        process = subprocess.Popen(
                            cmd,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT,
                            text=True,
                            bufsize=1
                        )
                        for line in iter(process.stdout.readline, ''):
                            print(line.strip())
                        return_code = process.wait()
                        if return_code == 0:
                            print("\n✓ 环境创建成功")
                        else:
                            print(f"\n✗ 环境创建失败，错误代码: {return_code}")
                            return
                        print(f"创建空间成功")
                        cls.reset_attr()
                    except Exception as e:
                        print(f"[错误] 创建空间失败: {e}")
                        return

            except KeyboardInterrupt:
                continue
            except EOFError:
                break

    @classmethod
    def reset_attr(cls):
        """
        重置属性
        """
        cls.new_space_name = ""  # 空间名
        cls.new_space_path = ""  # 空间路径
        cls.env_yml_content = ""  # env yml 内容
        cls.settings_content = ""  # settings.json 内容
        cls.py_version = ""  # python 版本


class ReplicateSpacePage(BasePage):
    """
    复制空间页面
    """
    current_space_index = ""
    new_space_name = ""
    new_space_path = ""
    space_content = ""

    @classmethod
    def prompt(cls, spaces=None):

        print(f"\n【复制空间】")
        print("-------------------------------")
        print("当前空间列表：")
        for i, item in enumerate(spaces):
            if item.get("status") is not None and item.get("status") == SpaceStatus.CACHE:
                print(f"{i + 1}. {item.get('name')}【缓存】: {item.get('path')}")
            else:
                print(f"{i + 1}. {item.get('name')}: {item.get('path')}")

        print("-------------------------------")
        print(f"当前选择的空间：{cls.current_space_index}")
        print(f"新空间的名称：{cls.new_space_name}")
        print(f"新空间的路径：{cls.new_space_path}")
        print("-------------------------------")
        print(f"0. 返回上级")
        print(f"1. 选择空间")
        print(f"2. 输入新空间名称")
        print(f"3. 输入新空间路径")
        print(f"4. 编辑新空间配置")
        print(f"5. 缓存空间")
        print(f"6. 开始复制空间")
        # print(f"7. 创建环境")
        print("输入 exit，回车，退出\n")

    @classmethod
    def process(cls, session):
        cls.reset_attr()

        while True:
            spaces = ControlCenter.get_all_space_path()
            cls.prompt(spaces)

            op_index = session.prompt('请选择业务[1, 2, 3, 4， 5, 6]：').strip()
            if op_index.lower() == 'exit':
                sys.exit("Exiting...")
            if op_index == "0":
                # 返回上级
                return

            try:
                if spaces is None:
                    spaces = {}
                if op_index == "1":
                    if len(spaces) == 1:
                        user_input = session.prompt(f'请输入空间索引[1]：').strip()
                    else:
                        user_input = session.prompt(f'请输入空间索引[1: {len(spaces)}]：').strip()

                    # 校验 index, 是否是整型, 是否是有效的空间索引
                    if not str.isdigit(user_input):
                        print("无效的空间索引.")
                        if len(spaces) == 1:
                            print(f"请输入整数.")
                        else:
                            print(f"请输入 [1 ~ {len(spaces)}] 之间的整数.")
                        continue

                    user_input = int(user_input)
                    if user_input < 0 or user_input > len(spaces):
                        print("无效的空间索引.")
                        print(f"请输入 [1 ~ {len(spaces)}] 之间的整数.")
                        continue
                    cls.current_space_index = user_input

                    index_space_info = spaces[cls.current_space_index - 1]
                    if index_space_info.get("status") is not None and index_space_info.get("status") == SpaceStatus.CACHE:
                        if cls.new_space_name.strip() == "":
                            cls.new_space_name = index_space_info.get("name")
                        if os.path.exists(os.path.join(COSPACE_CACHE_TMP_PATH, f"{cls.new_space_name}.json")):
                            with open(os.path.join(COSPACE_CACHE_TMP_PATH, f"{cls.new_space_name}.json"), "r", encoding="utf-8-sig") as f:
                                cls.space_content = f.read()
                        continue
                    else:
                        if os.path.exists(os.path.join(index_space_info.get("path"), "settings.json")):
                            with open(os.path.join(index_space_info.get("path"), "settings.json"), "r",
                                      encoding="utf-8-sig") as f:
                                cls.space_content = f.read()
                        continue

                elif op_index == "2":
                    cls.new_space_name = session.prompt(f"新的空间名称：").strip()
                    if not cls.new_space_name:
                        print("新空间名称不能为空.")
                        continue
                    temp_space_info = ControlCenter.get_space_info(cls.new_space_name)
                    if temp_space_info:
                        print(f"新空间名称已经存在.({temp_space_info})")
                        print("请重新输入新空间名称.")
                        cls.new_space_name = ""
                        continue

                    if cls.current_space_index:
                        src_space_name = spaces[cls.current_space_index - 1].get("name")
                        src_space_info = ControlCenter.get_space_info(src_space_name)
                        if src_space_info.status == SpaceStatus.CACHE:
                            if cls.new_space_name.strip() == src_space_name:
                                continue
                            # 更新缓存文件的名称
                            ControlCenter.update_cache_space_name(src_space_name, cls.new_space_name)

                elif op_index == "3":
                    cls.new_space_path = session.prompt(f"新的空间路径：").strip()
                    if os.path.exists(cls.new_space_path):
                        if os.path.exists(os.path.join(cls.new_space_path, "settings.json")):
                            print("新空间路径已经存在.")
                            print("请重新输入新空间路径.")
                            cls.new_space_path = ""
                            continue

                elif op_index == "4":
                    # 打开新的 Editor, 编辑新空间配置
                    if not cls.current_space_index:
                        print("请选择一个空间.")
                        continue

                    src_space_name = spaces[cls.current_space_index - 1].get("name")
                    src_space_info = ControlCenter.get_space_info(src_space_name)
                    if src_space_info.status == SpaceStatus.CACHE:
                        with open(os.path.join(COSPACE_CACHE_TMP_PATH, f"{src_space_name}.json"), "r", encoding="utf-8-sig") as f:
                            cls.space_content = f.read()
                    else:
                        with open(src_space_info.setting_path, "r", encoding="utf-8-sig") as f:
                            cls.space_content = f.read()

                    editor = Editor(content=cls.space_content)
                    result, msg = editor.run()
                    if result:
                        cls.space_content = msg
                        print(f"编辑器退出，返回上级菜单")
                    else:
                        print(f"编辑器退出，返回上级菜单，错误信息：{msg}")

                elif op_index == "5":
                    if not cls.current_space_index:
                        print("请选择一个空间.")
                        continue
                    if not cls.new_space_name:
                        print("请输入新的空间名称.")
                        continue
                    if not cls.new_space_path:
                        print("请输入新的空间路径.")
                        continue

                    index_space_info = spaces[cls.current_space_index - 1]
                    if not cls.space_content:
                        if index_space_info.get("status") is not None and index_space_info.get("status") == SpaceStatus.CACHE:
                            if os.path.exists(os.path.join(COSPACE_CACHE_TMP_PATH, f"{cls.new_space_name}.json")):
                                with open(os.path.join(COSPACE_CACHE_TMP_PATH, f"{cls.new_space_name}.json"), "r", encoding="utf-8-sig") as f:
                                    cls.space_content = f.read()
                        else:
                            if os.path.exists(os.path.join(index_space_info.get("path"), "settings.json")):
                                with open(os.path.join(index_space_info.get("path"), "settings.json"), "r", encoding="utf-8-sig") as f:
                                    cls.space_content = f.read()
                        if cls.space_content.strip() == "":
                            print("请编辑新空间配置.")
                            continue

                    # 缓存空间
                    print(f"开始缓存空间")
                    ControlCenter.create_cache_space(cls.new_space_name, cls.new_space_path, cls.space_content)
                    if index_space_info.get("conda_yaml_path"):
                        ControlCenter.update_cache_env_config(cls.new_space_name, yaml_path=index_space_info.get("conda_yaml_path"))
                    print(f"缓存成功")

                elif op_index == "6":
                    if not cls.current_space_index:
                        print("请选择一个空间.")
                        continue
                    if not cls.new_space_name:
                        print("请输入新的空间名称.")
                        continue
                    if not cls.new_space_path:
                        print("请输入新的空间路径.")
                        continue
                    if not cls.space_content:
                        print("请编辑新空间配置.")
                        continue

                    # 复制空间
                    src_space_name = spaces[cls.current_space_index - 1].get("name")
                    src_space_info = ControlCenter.get_space_info(src_space_name)
                    ControlCenter.create_space_by_content(src_space_info, cls.new_space_name, cls.new_space_path, cls.space_content)

                    # # 1.开始复制空间
                    # print(f"开始复制空间")
                    # # 2.缓存空间
                    # print(f"开始缓存空间")
                    # ControlCenter.create_cache_space(cls.new_space_name, cls.new_space_path, cls.space_content)
                    # print(f"缓存成功")
                    # # 3.创建空间
                    # ControlCenter.create_space_by_cache(cls.new_space_name)
                    # # 4.删除缓存
                    # ControlCenter.del_cache_space(cls.new_space_name)
                    # # 5.更新空间记录
                    # ControlCenter.update_space_record(cls.new_space_name, cls.new_space_path)
                    # print(f"复制成功")
                    cls.reset_attr()

                # elif op_index == "7":
                #     # 测试用
                #     if not cls.current_space_index:
                #         print("请选择一个空间.")
                #         continue
                #
                #     # 创建环境
                #     src_space_name = spaces[cls.current_space_index - 1].get("name")
                #     ControlCenter.create_env(src_space_name)
                #     cls.reset_attr()

            except KeyboardInterrupt:
                continue
            except EOFError:
                break

    @classmethod
    def reset_attr(cls):
        """
        重置属性
        """
        cls.current_space_index = ""
        cls.new_space_name = ""
        cls.new_space_path = ""
        cls.space_content = ""
